home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / cvs / sprite / update.save < prev   
Text File  |  1991-09-11  |  14KB  |  513 lines

  1. #ifndef lint
  2. static char rcsid[] = "$Id: update.c,v 1.2 91/09/10 16:12:36 jhh Exp Locker: jhh $";
  3. #endif !lint
  4.  
  5. /*
  6.  *    Copyright (c) 1989, Brian Berliner
  7.  *
  8.  *    You may distribute under the terms of the GNU General Public License
  9.  *    as specified in the README file that comes with the CVS 1.0 kit.
  10.  *
  11.  *    "update" updates the version in the present directory with respect to
  12.  *    the RCS repository.  The present version must have been created by
  13.  *    "checkout".  The user can keep up-to-date by calling "update" whenever
  14.  *    he feels like it.
  15.  *
  16.  *    The present version can be committed by "commit", but this keeps the
  17.  *    version in tact.
  18.  *
  19.  *    "update" accepts the following options:
  20.  *        -p    Prunes empty directories
  21.  *        -l    Local; does not do a recursive update
  22.  *        -q    Quiet; does not print a message when
  23.  *                recursively updating
  24.  *        -Q    Really quiet
  25.  *        -d    Directory; causes update to create new directories
  26.  *                as they are added to the RCS repository
  27.  *        -f    Forces a match for the -r revision
  28.  *        -r tag    Revision; only extract from revision "tag"
  29.  *        -D date    Updates to the revision specified by "date"
  30.  *
  31.  *    Arguments following the options are taken to be file names
  32.  *    to be updated, rather than updating the entire directory.
  33.  *
  34.  *    Modified or non-existent RCS files are checked out and reported
  35.  *    as U <user_file>
  36.  *
  37.  *    Modified user files are reported as M <user_file>.  If both the
  38.  *    RCS file and the user file have been modified, the user file
  39.  *    is replaced by the result of rcsmerge, and a backup file is
  40.  *    written for the user in .#file.version.  If this throws up
  41.  *    irreconcilable differences, the file is reported as C <user_file>,
  42.  *    and as M <user_file> otherwise.
  43.  *
  44.  *    Files added but not yet committed are reported as A <user_file>.
  45.  *    Files removed but not yet decommitted are reported as R <user_file>.
  46.  *
  47.  *    If the current directory contains subdirectories that hold
  48.  *    concurrent versions, these are updated too.  If the -d option
  49.  *    was specified, new directories added to the repository are
  50.  *    automatically created and updated as well.
  51.  */
  52.  
  53. #include <sys/param.h>
  54. #include <sys/types.h>
  55. #include <sys/stat.h>
  56. #include <dirent.h>
  57. #include "cvs.h"
  58.  
  59. char update_dir[MAXPATHLEN];
  60. int update_recursive = 1;
  61. int update_build_dirs = 0;
  62. int update_prune_dirs = 0;
  63.  
  64. static int really_recursive = 1;
  65.  
  66. update(argc, argv)
  67.     int argc;
  68.     char *argv[];
  69. {
  70.     FILE *fp;
  71.     int c, err = 0;
  72.  
  73.     if (argc == -1)
  74.     update_usage();
  75.     optind = 1;
  76.     while ((c = getopt(argc, argv, "pflQqdr:D:")) != -1) {
  77.     switch (c) {
  78.     case 'l':
  79.         really_recursive = 0;
  80.         update_recursive = 0;
  81.         break;
  82.     case 'Q':
  83.         really_quiet = 1;
  84.         /* FALL THROUGH */
  85.     case 'q':
  86.         quiet = 1;
  87.         break;
  88.     case 'd':
  89.         update_build_dirs = 1;
  90.         break;
  91.     case 'f':
  92.         force_tag_match = 1;
  93.         break;
  94.     case 'r':
  95.         (void) strcpy(Tag, optarg);
  96.         break;
  97.     case 'D':
  98.         Make_Date(optarg, Date);
  99.         break;
  100.     case 'p':
  101.         update_prune_dirs = 1;
  102.         break;
  103.     case '?':
  104.     default:
  105.         update_usage();
  106.         break;
  107.     }
  108.     }
  109.     argc -= optind;
  110.     argv += optind;
  111.     if (!isdir(CVSADM)) {
  112.     if (!quiet)
  113.         warn(0, "warning: no %s directory found", CVSADM);
  114.     if (argc <= 0) {
  115.         err += update_descend(update_recursive);
  116.     } else {
  117.         int i;
  118.  
  119.         for (i = 0; i < argc; i++) {
  120.         if (isdir(argv[i])) {
  121.             (void) strcat(Dlist, " ");
  122.             (void) strcat(Dlist, argv[i]);
  123.         } else {
  124.             warn(0, "nothing known about %s", argv[i]);
  125.             err++;
  126.         }
  127.         }
  128.         err += update_process_lists();
  129.     }
  130.     return (err);
  131.     }
  132.     Name_Repository();
  133.     Reader_Lock();
  134.     if (argc <= 0) {
  135.     /*
  136.      * When updating the entire directory, and recursively building
  137.      * directories, must make sure that the "static" file in the
  138.      * administration is removed before calling Find_Names().
  139.      */
  140.     if (update_build_dirs)
  141.         (void) unlink(CVSADM_ENTSTAT);
  142.     if (force_tag_match && (Tag[0] != '\0' || Date[0] != '\0'))
  143.         Find_Names(&fileargc, fileargv, ALLPLUSATTIC);
  144.     else
  145.         Find_Names(&fileargc, fileargv, ALL);
  146.     fp = open_file(CVSADM_MOD, "w+"); /* create a NULL Mod file */
  147.     (void) fclose(fp);
  148.     argc = fileargc;
  149.     argv = fileargv;
  150.     } else {
  151.     /*
  152.      * Not recursive if files were specified on the command line
  153.      */
  154.     update_recursive = 0;
  155.     }
  156.     if (Collect_Sets(argc, argv) != 0)
  157.     error(0, "failed; correct the above errors first");
  158.     free_names(&fileargc, fileargv);
  159.     err += update_process_lists();
  160.     /*
  161.      * XXX - Might be nice to sort the Mod file here, removing unique
  162.      * entries as we go, but it's currently not necessary, as "diff"
  163.      * is the only one that uses it, and he does the sort "as needed".
  164.      */
  165.     Lock_Cleanup(0);
  166.     /*
  167.      * Make directories, and descend them if requested to.
  168.      */
  169.     err += update_make_dirs(update_build_dirs && update_recursive);
  170.     err += update_descend(update_recursive);
  171.     Lock_Cleanup(0);
  172.     return (err);
  173. }
  174.  
  175. /*
  176.  * Process the lists created by Collect_Sets().
  177.  */
  178. static
  179. update_process_lists()
  180. {
  181.     char backup[MAXPATHLEN], dlist[MAXLISTLEN];
  182.     FILE *fp;
  183.     char *cp;
  184.     int update_Files = 0, err = 0;
  185.  
  186.     /*
  187.      * Wlist is the "remove entry" list.
  188.      */
  189.     for (cp = strtok(Wlist, " \t"); cp; cp = strtok((char *)NULL, " \t")) {
  190.     update_Files = 1;
  191.     (void) strcpy(User, cp);
  192.     Scratch_Entry(User);
  193.     if (!really_quiet) {
  194.         if (update_dir[0])
  195.         printf("D %s/%s\n", update_dir, User);
  196.         else
  197.         printf("D %s\n", User);
  198.     }
  199.     (void) unlink(User);
  200.     }
  201.     /*
  202.      * Olist is the "needs checking out" list.
  203.      */
  204.     for (cp = strtok(Olist, " \t"); cp; cp = strtok((char *)NULL, " \t")) {
  205.     update_Files = 1;
  206.     (void) strcpy(User, cp);
  207.     Locate_RCS();
  208.     (void) sprintf(backup, "%s/%s%s", CVSADM, CVSPREFIX, User);
  209.     if (isreadable(User))
  210.         rename_file(User, backup);
  211.     else
  212.         (void) unlink(backup);
  213.     if (Tag[0] != '\0' || Date[0] != '\0') {
  214.         Version_Number(Rcs, Tag, Date, VN_Rcs);
  215.         (void) sprintf(prog, "%s/%s -q -r%s %s %s", Rcsbin, RCS_CO,
  216.                VN_Rcs, Rcs, User);
  217.     } else {
  218.         (void) sprintf(prog, "%s/%s -q %s %s", Rcsbin, RCS_CO, Rcs, User);
  219.     }
  220.     if (system(prog) == 0) {
  221.         if (cvswrite == TRUE)
  222.         xchmod(User, 1);
  223.         Version_TS(Rcs, Tag, User);
  224.         Register(User, VN_Rcs, TS_User);
  225.         if (!really_quiet) {
  226.         if (update_dir[0])
  227.             printf("U %s/%s\n", update_dir, User);
  228.         else
  229.             printf("U %s\n", User);
  230.         }
  231.     } else {
  232.         if (isreadable(backup))
  233.         rename_file(backup, User);
  234.         warn(0, "could not check out %s", User);
  235.         err++;
  236.     }
  237.     (void) unlink(backup);
  238.     }
  239.     /*
  240.      * Mlist is the "modified, needs checking in" list.
  241.      */
  242.     for (cp = strtok(Mlist, " \t"); cp; cp = strtok((char *)NULL, " \t")) {
  243.     update_Files = 1;
  244.     (void) strcpy(User, cp);
  245.     if (!really_quiet) {
  246.         if (update_dir[0])
  247.         printf("M %s/%s\n", update_dir, User);
  248.         else
  249.         printf("M %s\n", User);
  250.     }
  251.     fp = open_file(CVSADM_MOD, "a");
  252.     if (fprintf(fp, "%s\n", User) == EOF)
  253.         error(1, "cannot write %s", CVSADM_MOD);
  254.     (void) fclose(fp);
  255.     }
  256.     /*
  257.      * Alist is the "to be added" list.
  258.      */
  259.     for (cp = strtok(Alist, " \t"); cp; cp = strtok((char *)NULL, " \t")) {
  260.     update_Files = 1;
  261.     (void) strcpy(User, cp);
  262.     if (!really_quiet) {
  263.         if (update_dir[0])
  264.         printf("A %s/%s\n", update_dir, User);
  265.         else
  266.         printf("A %s\n", User);
  267.     }
  268.     }
  269.     /*
  270.      * Rlist is the "to be removed" list.
  271.      */
  272.     for (cp = strtok(Rlist, " \t"); cp; cp = strtok((char *)NULL, " \t")) {
  273.     update_Files = 1;
  274.     (void) strcpy(User, cp);
  275.     if (!really_quiet) {
  276.         if (update_dir[0])
  277.         printf("R %s/%s\n", update_dir, User);
  278.         else
  279.         printf("R %s\n", User);
  280.     }
  281.     }
  282.     /*
  283.      * Glist is the "modified, needs merging" list.
  284.      *
  285.      * The users currently modified file is moved to a backup file
  286.      * name ".#filename.version", so that it will stay around for about
  287.      * three days before being automatically removed by some cron
  288.      * daemon.  The "version" is the version of the file that the
  289.      * user was most up-to-date with before the merge.
  290.      */
  291.     for (cp = strtok(Glist, " \t"); cp; cp = strtok((char *)NULL, " \t")) {
  292.     update_Files = 1;
  293.     (void) strcpy(User, cp);
  294.     Locate_RCS();
  295.     Version_TS(Rcs, Tag, User);
  296.     (void) sprintf(backup, "%s%s.%s", BAKPREFIX, User, VN_User);
  297.     (void) unlink(backup);
  298.     copy_file(User, backup);
  299.     xchmod(User, 1);
  300.     (void) sprintf(prog, "%s/%s -r%s %s", Rcsbin, RCS_MERGE,
  301.                VN_User, Rcs);
  302.     if (system(prog) != 0) {
  303.         warn(0, "could not merge revision %s of %s",
  304.          VN_User, User);
  305.         warn(0, "backup file for %s is in %s", User, backup);
  306.         err++;
  307.         continue;
  308.     }
  309.     Register(User, VN_Rcs, TS_Rcs);
  310.     (void) sprintf(prog, "%s -s '%s' %s", GREP, RCS_MERGE_PAT, User);
  311.     if (system(prog) == 0) {
  312.         warn(0, "conflicts found in %s", User);
  313.         if (!really_quiet) {
  314.         if (update_dir[0])
  315.             printf("C %s/%s\n", update_dir, User);
  316.         else
  317.             printf("C %s\n", User);
  318.         }
  319.     } else {
  320.         if (!really_quiet) {
  321.         if (update_dir[0])
  322.             printf("M %s/%s\n", update_dir, User);
  323.         else
  324.             printf("M %s\n", User);
  325.         }
  326.     }
  327.     fp = open_file(CVSADM_MOD, "a");
  328.     if (fprintf(fp, "%s\n", User) == EOF)
  329.         error(1, "cannot write %s", CVSADM_MOD);
  330.     (void) fclose(fp);
  331.     }
  332.     if (Dlist[0]) {
  333.     int save_recursive = update_recursive;
  334.  
  335.     update_recursive = really_recursive;
  336.     Lock_Cleanup(0);        /* cleanup locks before descending */
  337.     (void) strcpy(dlist, Dlist);    /* to get it on the stack... */
  338.     for (cp = strtok(dlist, " \t"); cp; cp = strtok((char *)NULL, " \t")) {
  339.         err += update_descend_dir(cp);
  340.     }
  341.     update_recursive = save_recursive;
  342.     }
  343.     if (update_Files != 0)
  344.     Entries2Files();
  345.     return (err);
  346. }
  347.  
  348. /*
  349.  * When automatically creating directories from the repository in the
  350.  * local work directory, we scan for directories that don't exist locally
  351.  * and create them with a NULL administration directory for now, which
  352.  * is filled by update later.
  353.  */
  354. static
  355. update_make_dirs(doit)
  356.     int doit;
  357. {
  358.     char fname[MAXPATHLEN], tmp[MAXPATHLEN];
  359.     DIR *dirp;
  360.     struct dirent *dp;
  361.     int err = 0;
  362.  
  363.     if (doit) {
  364.     if ((dirp = opendir(Repository)) == NULL) {
  365.         warn(0, "cannot open directory %s", Repository);
  366.         err++;
  367.     } else while ((dp = readdir(dirp)) != NULL) {
  368.         if (strcmp(dp->d_name, ".") == 0 ||
  369.         strcmp(dp->d_name, "..") == 0 ||
  370.         strcmp(dp->d_name, CVSATTIC) == 0 ||
  371.         strcmp(dp->d_name, CVSLCK) == 0)
  372.         continue;
  373.         (void) sprintf(fname, "%s/%s", Repository, dp->d_name);
  374.         (void) sprintf(tmp, "%s/%s", dp->d_name, CVSADM);
  375.         if (!isdir(fname))
  376.         continue;
  377.         if (islink(dp->d_name) || isdir(tmp))
  378.         continue;
  379.         if (!isdir(dp->d_name) && isfile(dp->d_name)) {
  380.         warn(0, "file %s should be a directory; please move it", dp->d_name);
  381.         err++;
  382.         } else {
  383.         make_directory(dp->d_name);
  384.         if (chdir(dp->d_name) < 0) {
  385.             warn(0, "cannot chdir to %s", dp->d_name);
  386.             err++;
  387.         } else {
  388.             (void) strcpy(tmp, Repository);
  389.             (void) strcpy(Repository, fname);
  390.             Create_Admin(Repository, DFLT_RECORD);
  391.             (void) chdir("..");
  392.             (void) strcpy(Repository, tmp);
  393.         }
  394.         }
  395.     }
  396.     if (dirp)
  397.         (void) closedir(dirp);
  398.     }
  399.     return (err);
  400. }
  401.  
  402. /*
  403.  * If doalldirs is set, does a recursive update by calling update_descend_dir()
  404.  * for each file in the current directory.
  405.  */
  406. static
  407. update_descend(doalldirs)
  408.     int doalldirs;
  409. {
  410.     DIR *dirp;
  411.     struct dirent *dp;
  412.     int err = 0;
  413.  
  414.     if (doalldirs) {
  415.     if ((dirp = opendir(".")) == NULL) {
  416.         err++;
  417.     } else {
  418.         while ((dp = readdir(dirp)) != NULL) {
  419.         if (strcmp(dp->d_name, ".") == 0 ||
  420.             strcmp(dp->d_name, "..") == 0)
  421.             continue;
  422.         err += update_descend_dir(dp->d_name);
  423.         }
  424.         (void) closedir(dirp);
  425.     }
  426.     }
  427.     return (err);
  428. }
  429.  
  430. /*
  431.  * This is the recursive function that walks the argument directory looking
  432.  * for sub-directories that have CVS administration files in them
  433.  * and updates them recursively.
  434.  *
  435.  * Note that we do not follow symbolic links here, which is a feature!
  436.  */
  437. static
  438. update_descend_dir(dir)
  439.     char *dir;
  440. {
  441.     char cwd[MAXPATHLEN], fname[MAXPATHLEN];
  442.     char *cp;
  443.     int err;
  444.  
  445.     (void) sprintf(fname, "%s/%s", dir, CVSADM);
  446.     if (!isdir(dir) || islink(dir) || !isdir(fname))
  447.     return (0);
  448.     if (getwd(cwd) == NULL) {
  449.     warn(0, "cannot get working directory: %s", cwd);
  450.     return (1);
  451.     }
  452.     if (update_dir[0] == '\0')
  453.     (void) strcpy(update_dir, dir);
  454.     else {
  455.     (void) strcat(update_dir, "/");
  456.     (void) strcat(update_dir, dir);
  457.     }
  458.     if (!quiet)
  459.     printf("%s %s: Updating %s\n", progname, command, update_dir);
  460.     if (chdir(dir) < 0) {
  461.     warn(1, "cannot chdir to %s", update_dir);
  462.     err = 1;
  463.     goto out;
  464.     }
  465.     err = update(0, (char **)0);
  466.     if ((cp = rindex(update_dir, '/')) != NULL)
  467.     *cp = '\0';
  468.     else
  469.     update_dir[0] = '\0';
  470. out:
  471.     if (chdir(cwd) < 0)
  472.     error(1, "cannot chdir to %s", cwd);
  473.     if (update_prune_dirs && isemptydir(dir)) {
  474.     (void) sprintf(prog, "%s -fr %s", RM, dir);
  475.     (void) system(prog);
  476.     }
  477.     return (err);
  478. }
  479.  
  480. /*
  481.  * Returns 1 if the argument directory is completely empty, other than
  482.  * the existence of the CVS.adm directory entry.  Zero otherwise.
  483.  */
  484. isemptydir(dir)
  485.     char *dir;
  486. {
  487.     DIR *dirp;
  488.     struct dirent *dp;
  489.  
  490.     if ((dirp = opendir(dir)) == NULL) {
  491.         warn(0, "cannot open directory %s for empty check", dir);
  492.     return (0);
  493.     }
  494.     while ((dp = readdir(dirp)) != NULL) {
  495.         if (strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0 &&
  496.             strcmp(dp->d_name, CVSADM) != 0) {
  497.             (void) closedir(dirp);
  498.             return (0);
  499.         }
  500.     }
  501.     (void) closedir(dirp);
  502.     return (1);
  503. }
  504.  
  505. static
  506. update_usage()
  507. {
  508.     (void) fprintf(stderr,
  509.            "Usage: %s %s [-Qqlfp] [-d] [-r tag|-D date] [files...]\n",
  510.            progname, command);
  511.     exit(1);
  512. }
  513.